<?php

namespace App\Sdks\Ali\Traits;

use App\Common\Tools\CustomException;

trait Request
{
    /**
     * @param $action
     * @param array $param
     * @param string $method
     * @param array $header
     * @return bool|string
     * @throws CustomException
     * 公共请求
     */
    public function publicRequest($action, $param = [], $method = 'GET', $header = []){
        // 设置时区为 UTC
        date_default_timezone_set("UTC");

        $date = date('Y-m-d', TIMESTAMP);
        $time = date('H:i:s', TIMESTAMP);

        // 公共参数
        $publicParam = [
            'AccessKeyId' => $this->getAccessKeyId(),
            'Action' => $action,
            'Format' => 'json',
            'SignatureMethod' => 'HMAC-SHA1',
            'SignatureNonce' => uniqid(),
            'SignatureVersion' => '1.0',
            'Timestamp' => "{$date}T{$time}Z",
            'Version' => '2017-05-25',
        ];

        $param = array_merge($publicParam, $param);

        // 签名
        $param['Signature'] = $this->getSignature($param, $method);

        $ret = $this->curlRequest(self::BASE_URL, $param, $method, $header);

        $result = json_decode($ret, true);

        if(empty($result) || $result['Message'] != 'OK'){
            throw new CustomException([
                'code' => 'SEND_SMS_FAIL',
                'message' => '发送短信验证码失败',
                'log' => true,
                'data' => [
                    'param' => $param,
                    'ret' => $ret,
                ],
            ]);
        }

        return $result;
    }

    /**
     * @param $params
     * @param $method
     * @return string
     * 获取签名
     */
    protected function getSignature($params, $method){
        //移除签名字段
        if(isset($params['Signature'])){
            unset($params['Signature']);
        }

        //字典排序
        ksort($params);

        //urlencode
        $tmp = [];
        foreach($params as $k => $v){
            $tmp[] = $this->percentEncode($k) .'='. $this->percentEncode($v);
        }
        $string = implode("&", $tmp);

        $stringToSign = strtoupper($method) .'&%2F&'. $this->percentEncode($string);

        // sha1
        $sha1 = hash_hmac('sha1', utf8_encode($stringToSign), $this->getAccessKeySecret() .'&', true);

        return base64_encode($sha1);
    }

    /**
     * @param $string
     * @return mixed
     * 特殊符号处理
     */
    protected function percentEncode($string){
        $string = urlencode($string);
        return str_replace(["+", "*", "%7E"], ["%20", "%2A", ""], $string);
    }

    /**
     * @param $url
     * @param $param
     * @param string $method
     * @param array $header
     * @return bool|string
     * CURL请求
     */
    private function curlRequest($url, $param = [], $method = 'GET', $header = []){
        $method = strtoupper($method);
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

        $header = array_merge($header, ['Connection: close']);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

        if(stripos($url, 'https://') === 0){
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER , false);
        }

        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);

        if($method == 'POST'){
            curl_setopt($ch, CURLOPT_POST, true);
        }

        curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
        curl_setopt($ch, CURLOPT_TIMEOUT, 15);

        $result = curl_exec($ch);
        curl_close($ch);

        return $result;
    }
}
